/**
*
* @file
*		heap_test_julia
*
* @brief
*		Tests for heap by julia
*/

#include "../../src/khlamov/heap_kh.h"
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <iostream>
using namespace std;

//#define print_me(); ((heap_julia*)hp)->print_all();
/**
 * abstract test
 */

void ThreadMain(LPVOID hp)
{
	const int amount=3000;
	int num;
	char* num1;
	char* alloced[amount];
	memset(alloced,0,amount);
	int l=1;
	for (int i=0;i<amount;i++)
	{	
	if ((rand() % 3)==1)
		{
			num=(int)(rand()%(128*4));
			
						printf("Trying to allocate at %d\n",num);
			alloced[l]=(char*)((heap876*)hp)->alloc(num,rand()%5);
			if (alloced[l]!=0)
			l++;
	//		print_me();
	    }
		if (rand() % 3==1)
		{
			num1=alloced[rand() % l];
						printf("Trying to free at %x\n",num1);
			((heap876*)hp)->free(num1);
		//	print_me();
		}
		if (rand() % 3==2)
		{
			unsigned int tag=rand() % 5;
						printf("Trying to free_all at tag %d\n",tag);
			((heap876*)hp)->free_all(tag);
			//print_me();
		}
	}

}

int test( heap876* hp )
{
	hp->get_volume();
	printf("heap<%s> volume is %d\n", hp->get_name(), hp->get_volume());
	srand((unsigned int)time(0));

	//print_me();

	/*for (int i=0;i<30;i++) // random generated test
	{	if ((rand() % 2)==1)
		{
			hp->alloc((int)(rand()%(128*21)),rand());
			print_me();
	    }
		if (rand() % 2==1)
		{
			hp->free((char*)(((heap_julia*)hp)->memory + (char)(rand() % 128)));
			print_me();
		}
	}
	*/



	/* //one-thread test
	cout << "checking if program can allocate less than size_of_block size \n Expected result -- OK \n";
    char** t=(char**)hp->alloc(20,1);
	*t="I'm Julia, student of mipt";
   print_me();
   cout << "done \n\n";

   cout << "checking allocation of (size_of_block + 2) bytes \n  Expected result -- OK \n";
	char** t1=(char**)hp->alloc(130,2); 
	print_me();
	*t1 = "How are you doing?";
	cout << "done \n\n";

	cout << "trying to free memory that doesn't belong to the mem_array\n  Expected result -- Error \n";
	hp->free (t-1);
	print_me();
	cout << "done \n\n";

	cout << "trying to free memory that belongs to other program (middle of it)\n Expected result -- Error \n";
	hp->free (t1-1);
	print_me();
	cout << "done \n\n";

	cout << "trying to free memory that is free \n Expected result -- Error \n";
	hp->free (t1+140);
	print_me();
	cout << "done \n\n";

	cout << "trying to free memory that belogs to other program (beginning of it)\n  Expected result -- OK \n"; 
	hp->free (t+32);
	print_me();
	cout << "done \n\n";

	cout << "trying to free memory in the beginning\n  Expected result -- OK \n"; 
	hp->free (t);
	print_me(); 
	cout << "done \n\n";

	cout << "trying to allocate memory 11 times\n  Expected result -- OK \n"; 
	char*** t2=(char***)hp->alloc(1,1);
	print_me();
	for (int i=0;i<10;i++)
	{  t2[i]=(char**)hp->alloc(128*(2*i+1),i); print_me();}
	t2[10]=(char**)hp->alloc(128*19,10);
	 char ** t3=(char**)hp->alloc(127,3);
	print_me(); 
	cout << "done \n\n";

	cout << "trying to free memory in the middle\n  Expected result -- OK \n"; 
	hp->free(t2[5]);
	print_me(); 
	cout << "done \n\n";

	cout << "spoiling memory of other program + allocate 6 blocks\n  Expected result -- Error if alloc_debug\n"; 
	*(t2[5])="Hi";
	t2[5]=(char**)hp->alloc(128*6,6);
	print_me(); 
	cout << "done \n\n";

	cout << "allocating memory when it's not enough place\n  Expected result -- Error \n"; 
    t3=(char**)hp->alloc(128*7,3);
	print_me(); 
	cout << "done \n\n";

	cout << "cheking free_all. \n Expected result -- Error if not alloc_tagged\n"; 
	hp->free_all(1); 
	hp->free_all(3); 
	t2[3]=(char**)hp->alloc(128*7,2);
	hp->free_all(2);
	print_me();
	cout << "done \n\n";
	*/



//Multi-thread test
const int MAX_THREADS=5;
int i;
int* memory=(int*)hp->alloc((int)(rand()%(128*21)),rand()); //remembering the beginning of the memory in our allocator
DWORD   dwThreadIdArray[MAX_THREADS];
HANDLE  hThreadArray[MAX_THREADS]; 
for (i=0;i<MAX_THREADS;i++)
{
	hThreadArray[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadMain,hp, 0,&dwThreadIdArray[i]);  
        if (hThreadArray[i] == NULL) 
        {
           printf("CreateThreadError\n");
           ExitProcess(3);
        }
} 
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
for(int i=0; i<MAX_THREADS; i++)
CloseHandle(hThreadArray[i]);
	return 0;
}

/**
 * execution of test above your class
 */

int main( int argc, char* argv[] )
{
	try{
		heap_kh hp_kh(128*20, heap876::alloc_simple );
	test( &hp_kh );
	}
	catch(exception &e)
	{cout << e.what();}
	getchar();
	return 0;
}
